import 'dart:convert';
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:flutter_study_lib/utils/AppConfig.dart';
import 'package:flutter_study_lib/utils/ToolUtil.dart';
import 'package:package_info/package_info.dart';

class HttpData {
  int code;
  String msg;
  var data;
  
  HttpData.fromJson(Map<String,dynamic> json) 
          : code = json['code'],
            msg = json['msg'],
            data = json['data'];
  
  Map<String,dynamic> toJson() =>
  {
    'code':code,
    'msg':msg,
    'data':data
  };
}

class HttpUtil {
  static const String GET = "get";
  static const String POST = "post";

  static final HttpUtil _instance = HttpUtil._init();
  static Dio _dio;

  factory HttpUtil() {
    return _instance;
  }

  HttpUtil._init() {
    _dio = new Dio();
  }

  static BaseOptions getDefOptions() {
    BaseOptions options = BaseOptions();
    options.connectTimeout = 30 * 1000;
    options.receiveTimeout = 30 * 1000;
    options.contentType = ContentType.parse('application/json;charset=utf-8');

    Map<String, dynamic> headers = Map<String, dynamic>();
    headers['Accept'] = 'application/json';

    String platform;
    if(Platform.isAndroid) {
      platform = "Android";
    } else if(Platform.isIOS) {
      platform = "IOS";
    }
    headers['OS'] = platform;
    options.headers = headers;

    return options;
  }

  void get(String url,Function successCallBack,{Map<String,dynamic> params,Function failCallBack,String categoryCode}) {
     _request(AppConfig.baseUrl + url, successCallBack,method:GET,params: params,failCallBack: failCallBack);
  }

  void post(String url,Function successCallBack,{Map<String,dynamic> params,Function failCallBack,String categoryCode}) {
    _request(AppConfig.baseUrl + url, successCallBack,method:POST,params: params,failCallBack: failCallBack,categoryCode: categoryCode);
  }

  void _request(String url,Function successCallBack,{String method,Map<String, dynamic> params,Function failCallBack,String categoryCode}) async {
    print("<request> url :<" + method + ">" + url);
    if (params != null && params.isNotEmpty) {
      print("<request> params :" + params.toString());
    }
    try {
      String timestamp = DateTime.now().microsecondsSinceEpoch.toString();
      String signContent = await HttpUtil._signParam(params, timestamp);
      String basicParams = await HttpUtil._headerParams(signContent, timestamp,categoryCode: categoryCode);
      print("basicParams:" + basicParams);

      Map<String,dynamic> headers = {
        "basicParams":basicParams,
      };
      Options options = Options(
        method: method,
        connectTimeout: 10000,
        receiveTimeout: 10000,
        headers: headers
      );

      Response response = await _dio.request(url, data: params, options: options);
      if(response.statusCode == HttpStatus.ok || response.statusCode == HttpStatus.created) {
        HttpData httpData;
        if (response.data is Map) {
          print("response:" + '$response');
          httpData = HttpData.fromJson(response.data);
        }
        else {
          Map<String,dynamic> responseJson = json.decode(response.data.toString());
          print("response:" + '$responseJson');
          httpData = HttpData.fromJson(responseJson);
        }

        if (httpData.code == 700) {
            //重新登录
            AppConfig.setToken("");
          }
        else {
            if (successCallBack != null) {
              successCallBack(httpData);
            }
        }
      }
    }
    catch (exception) {
      print("exception:" + exception.toString());
      if (failCallBack != null) {
        failCallBack(exception.toString());
      }
    }
  }

  static Future<String> _signParam(Map<String,dynamic> param,String timestamp) async {
    String signContent = "";
    signContent += AppConfig.appKey;

    PackageInfo packageInfo = await PackageInfo.fromPlatform();
    String version = packageInfo.version;
    signContent += version;

    signContent += AppConfig.appClient;
    String buildVersion = packageInfo.buildNumber;
    signContent += buildVersion;

    signContent += timestamp;
    signContent += AppConfig.guestID;

    signContent += await AppConfig.getToken();

    if (param != null && param.isNotEmpty) {
      String paramJson = json.encode(param);
      signContent += paramJson;
    }
    signContent += AppConfig.appSecret;

    return ToolUtil.generateMD5(ToolUtil.generateMD5(signContent)) ;
  }

  static Future<String> _headerParams(String signContent, String timestamp,{String categoryCode = ""}) async {

  PackageInfo packageInfo = await PackageInfo.fromPlatform();
  String version = packageInfo.version;
  String buildVersion = packageInfo.buildNumber;

  var header = {
    "appKey":AppConfig.appKey,
    "appVersion":version,
    "channel":AppConfig.channel,
    "appClient":AppConfig.appClient,
    "openId":AppConfig.openId,
    "from":AppConfig.from,
    "clientId":AppConfig.clientId,
    "timestamp":timestamp,
    "net":"wifi",
    "versionCode":buildVersion,
    "token":await AppConfig.getToken(),
    "guestId":AppConfig.guestID,
    "appCode":AppConfig.appCode,
    "categoryCode":categoryCode,
    "appSign":signContent,
  };
  return json.encode(header);
}
}